#include "coremethods.h"
#include <QDebug>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QApplication>
#include <QMainWindow>
#include <QMessageBox>
#include <QString>
#include <QStringList>
#include <QWebFrame>
#include <QWebPage>
#include <QSettings>
#include <QMenuBar>
#include <QDesktopServices>
#include <QUrl>
#include <QDesktopWidget>
#include "hybridpluginmanager.h"

#if defined(Q_OS_SYMBIAN) && !defined(HAVE_NOKIAQTSDK)
#include <aknappui.h>
#include <apgcli.h> // for RApaLsSession
#include <apacmdln.h> // for CApaCommandLine
#endif

CoreMethods::CoreMethods(QMainWindow *parentWindow, 
						 QWebFrame *webFrame, 
						 HybridPluginManager *pluginManager, 
						 QString identifier) : 
	m_leftSoftkey(0), 
	m_rightSoftkey(0), 
	m_parentWindow(parentWindow), 
	m_webFrame(webFrame),
	m_pluginManager(pluginManager),
	m_identifier(identifier)
{    
}

void CoreMethods::appendMenuItem(const QString &label, 
								 const int id, const int parentId, 
								 const QString &onSelect)
{
    if(parentId == 0) // top level menu item
    {
        qDebug() << "append top level menu: " << label;
        QAction *action = new QAction(label, this);

        if(m_menuItems.count() == 0) {
//            m_webFrame->evaluateJavaScript("hybrid.menuOnShow.connect(menuOnShow);");
        }

        connect(action, SIGNAL(triggered()), this, SLOT(menuItemHandler()));
        m_parentWindow->menuBar()->addAction(action);
        MenuItem* mi = new MenuItem(label, id, parentId, onSelect, action);
        m_menuItems.insert(id, mi);
    }
    else // submenu item
    {
        qDebug() << "append submenu menu: " << label;
        // find parent and add new action to it
        if(m_menuItems.contains(parentId))
        {
            MenuItem *parentMenuItem = m_menuItems[parentId];
            QAction *act = parentMenuItem->m_qAction;
            if(!act->menu())
            {
                act->setMenu(new QMenu());
            }
            QAction *action = new QAction(label, this);
            connect(action, SIGNAL(triggered()), this, SLOT(menuItemHandler()));
            act->menu()->addAction(action);

            MenuItem *mi = new MenuItem(label, id, parentId, onSelect, action);
            m_menuItems.insert(id, mi);
        }
    }
}

void CoreMethods::menuHandler()
{
    qDebug() << "menuHandler called ";
    emit menuOnShow();
}

void CoreMethods::menuItemHandler()
{
    qDebug() << "menuItemHandler called ";
   MenuItem *item = menuItem(qobject_cast<QAction *>(sender()));

    if(item)
    {
        m_webFrame->evaluateJavaScript(item->m_handlerFunction+tr("(%1)").arg(item->m_id));
        //emit itemSelected(item->m_id);
    }
}

void CoreMethods::customSoftkeyHandler()
{
    QAction *act = qobject_cast<QAction *>(sender());

    if(m_leftSoftkey && act == m_leftSoftkey->m_qAction) {
        m_webFrame->evaluateJavaScript(m_leftSoftkey->m_handlerFunction+"()");
    }
    else if(m_rightSoftkey && act == m_rightSoftkey->m_qAction) {
        m_webFrame->evaluateJavaScript(m_rightSoftkey->m_handlerFunction+"()");
    }
}

void CoreMethods::setDimmed(const int id, bool flag)
{
    if(m_menuItems.contains(id))
    {
        MenuItem *mi = m_menuItems[id];

        if(mi->m_qAction)
            mi->m_qAction->setEnabled(!flag);
    }
    else
    {
        qDebug() << "wrong menu id" << id;
    }
}

void CoreMethods::remove(const int id)
{
    if(m_menuItems.contains(id))
    {
        MenuItem *mi = m_menuItems[id];
        qDebug() << "removing menu id" << id;

        QAction *act = mi->m_qAction;

        if(m_menuItems.contains(mi->m_parentId)) // remove submenu action
        {
            act = m_menuItems[mi->m_parentId]->m_qAction;
            act->menu()->removeAction(mi->m_qAction);
        }
        else // remove top level action
        {
            m_parentWindow->menuBar()->removeAction(act);
        }

        delete mi;
        m_menuItems.remove(id);
    }
}

void CoreMethods::clear()
{
    foreach (int i, m_menuItems.keys())
    {
        delete m_menuItems[i];
    }
    m_menuItems.clear();

    m_parentWindow->menuBar()->clear();
}

MenuItem *CoreMethods::menuItem(QAction *act)
{
    MenuItem *retval = 0;

    foreach (int i, m_menuItems.keys())
    {
        MenuItem *mi = m_menuItems[i];
        QAction *action = mi->m_qAction;
        if(action && action == act)
        {
            retval = mi;
            break;
        }
    }
    return retval;
}

void CoreMethods::showSoftkeys()
{
	qDebug() << "showing softkeys";
	((QWidget*)m_parentWindow)->showNormal();
    ((QWidget*)m_parentWindow)->update();
}

void CoreMethods::hideSoftkeys()
{
	qDebug() << "hiding softkeys";
#ifndef Q_OS_WIN
	m_parentWindow->showFullScreen();
	m_parentWindow->update();
#endif
}

void CoreMethods::setLeftSoftkeyLabel(const QString &label, const QString &callbackfunc)
{
        if(label.isEmpty() && callbackfunc.isEmpty()) // remove
        {
            removeSoftkey(false);

        }
        else // set
        {
            removeSoftkey(false);
            QAction *act = new QAction(label, m_parentWindow);
            act->setSoftKeyRole(QAction::PositiveSoftKey);
            connect(act, SIGNAL(triggered()), this, SLOT(customSoftkeyHandler()));
            m_parentWindow->addAction(act);
            m_leftSoftkey = new MenuItem(label, 0, 0, callbackfunc, act);
        }
}

void CoreMethods::setRightSoftkeyLabel(const QString &label, const QString &callbackfunc)
{
        if(label.isEmpty() && callbackfunc.isEmpty()) // remove
        {
            removeSoftkey(true);
        }
        else // set
        {
            removeSoftkey(true);
            QAction *act = new QAction(label, m_parentWindow);
            act->setSoftKeyRole(QAction::NegativeSoftKey);
            connect(act, SIGNAL(triggered()), this, SLOT(customSoftkeyHandler()));
            m_parentWindow->addAction(act);
            m_rightSoftkey = new MenuItem(label, 0, 0, callbackfunc, act);
        }
}

void CoreMethods::removeSoftkey(bool rightSoftkey)
{
    if(rightSoftkey)
    {
        if(m_rightSoftkey) {
            m_parentWindow->removeAction(m_rightSoftkey->m_qAction);
            delete m_rightSoftkey;
            m_rightSoftkey = 0;
        }
    }
    else
    {
        if(m_leftSoftkey) {
            m_parentWindow->removeAction(m_leftSoftkey->m_qAction);
            delete m_leftSoftkey;
            m_leftSoftkey = 0;
        }
    }
}


void CoreMethods::debugLog(const QString &line)
{
    qDebug() << line;
}

void CoreMethods::setPreferenceForKey(const QString &value, const QString &key)
{
	if(key != "")
	{
		QSettings settings("HAG", m_identifier);
		settings.setValue(key,value);
	}
}

QString CoreMethods::preferenceForKey(const QString &key)
{
	QSettings settings("HAG", m_identifier);
	QString value = settings.value(key).toString();
	return value;
}
    
void CoreMethods::setDisplayLandscape()
{
    #if defined(Q_OS_SYMBIAN) && !defined(HAVE_NOKIAQTSDK)
    CAknAppUi* appUi = static_cast<CAknAppUi*>(CEikonEnv::Static()->AppUi());
    if (appUi)
        appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape);
    #endif
}

void CoreMethods::setDisplayPortrait()
{
    #if defined(Q_OS_SYMBIAN) && !defined(HAVE_NOKIAQTSDK)
    CAknAppUi* appUi = static_cast<CAknAppUi*>(CEikonEnv::Static()->AppUi());
    if (appUi)
        appUi->SetOrientationL( CAknAppUi::EAppUiOrientationPortrait );
    #endif
}

void CoreMethods::setNavigationEnabled(bool mode)
{
#ifdef QT_KEYPAD_NAVIGATION
    QApplication::setNavigationMode (mode ? Qt::NavigationModeCursorForceVisible : Qt::NavigationModeKeypadDirectional);
    /*
    if(mode)
    {
        m_parentWindow->setFocusPolicy(Qt::StrongFocus);
        m_parentWindow->activateWindow();
    }
    */
#else
	Q_UNUSED(mode)
#endif
}

void CoreMethods::setNavigationType(const QString &navigationType)
{
    // TODO: validate the actual behaviour in each case. I'm not sure whether we've completely
    // identical modes in QWebKit but at least we can ensure that widgets work.

#ifdef QT_KEYPAD_NAVIGATION
    if(navigationType=="cursor")
    {
        QApplication::setNavigationMode (Qt::NavigationModeCursorForceVisible);
//        QApplication::setNavigationMode (Qt::NavigationModeCursorAuto);
        m_webFrame->page()->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain,true);
    }
    else if(navigationType=="tabbed")
    {
        QApplication::setNavigationMode (Qt::NavigationModeKeypadDirectional);
        m_webFrame->page()->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain,false);
    }
    else if(navigationType=="none")
    {
        QApplication::setNavigationMode (Qt::NavigationModeNone);
        m_webFrame->page()->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain,false);
    }
#else
	Q_UNUSED(navigationType)
#endif
}

void CoreMethods::prepareForTransition(const QString &transitionMode)
{
	Q_UNUSED(transitionMode);
}

void CoreMethods::performTransition()
{

}


void CoreMethods::openApplication(const int Uid, const QString &param)
{
#if defined(Q_OS_SYMBIAN) && !defined(HAVE_NOKIAQTSDK)
    RApaLsSession apaLsSession;
    User::LeaveIfError(apaLsSession.Connect());
    CleanupClosePushL(apaLsSession);
    TApaAppInfo appInfo;
    TUid uid;
    uid.iUid = Uid;
    TInt retVal = apaLsSession.GetAppInfo(appInfo, uid);
    if(retVal == KErrNone)
    {
        CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
        cmdLine->SetExecutableNameL(appInfo.iFullName);
        if(param.length()> 0)
        {
            TBuf<256> buffer(param.utf16());
            TBuf8<256> paramBuffer;
            paramBuffer.Copy(buffer);
            cmdLine->SetTailEndL(paramBuffer);
        }
        cmdLine->SetCommandL(EApaCommandRun);
        User::LeaveIfError( apaLsSession.StartApp(*cmdLine) );
        CleanupStack::PopAndDestroy(cmdLine);
    }
    else
    {
        // The application not found!
    }

    CleanupStack::PopAndDestroy(&apaLsSession);
#else
	Q_UNUSED(Uid)
	Q_UNUSED(param)
#endif
}

bool CoreMethods::rotationSupported()
{
    bool rotationSupport = false;
#if defined(Q_OS_SYMBIAN) && !defined(HAVE_NOKIAQTSDK)
    CCoeEnv* env = CCoeEnv::Static();
    if( env )
    {
        CAknAppUiBase* appUiBase = REINTERPRET_CAST( CAknAppUiBase*, env->AppUi() );
        if( appUiBase )
        {
        rotationSupport = appUiBase->OrientationCanBeChanged();
        }
    }
#endif
    return rotationSupport;
}


void CoreMethods::openURL(const QString &url)
{
    QDesktopServices::openUrl(QUrl(url));
}

bool CoreMethods::eventFilter(QObject *object, QEvent *event)
{
	Q_UNUSED(object)
	Q_UNUSED(event)
	return false;
}

QObject *CoreMethods::getPlugin(const QString &pluginName)
{
	qDebug() << "Loading plugin" << pluginName;
	QObject *pluginInstance = m_pluginManager->load(pluginName);
	HybridPluginInterface *plugin = qobject_cast<HybridPluginInterface *> (
					pluginInstance);
	
	plugin->setEnvironment(m_parentWindow, m_webFrame);
	
	if(plugin)
	{
		qDebug() << "Plugin was successfully loaded" << pluginName;
		return plugin->jsObjectInstance();
	}
	qDebug() << "Error when loading plugin" << pluginName;
	return 0;
}

QString CoreMethods::widgetIdentifier()
{
    return m_identifier;
}
